package hz.mobileproject.pda.push.mqtt;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.blankj.utilcode.util.DeviceUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ToastUtils;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import hz.mobileproject.pda.network.Constance;

public class MqttClientMgr {
    private static final String TAG = MqttClientMgr.class.getSimpleName();
    public static final String CLIENT_ID = "CLIENT_ID_" + DeviceUtils.getMacAddress();
    public static final String ACTION_CONNECTION_LOST = "connectionLost";
    public static final String ACTION_MESSAGE_ARRIVED = "messageArrived";
    private String userName = "admin";
    private String passWord = "password";
    private MqttClient mClient;
    private boolean mbIsReconnect;
    private Context mContext;
    private static MqttClientMgr mInstance;
    //存储已订阅字段
    private List<String> mTopWordList = new ArrayList<>();

    private ScheduledExecutorService scheduler;

    private MqttCallback mQttCallback = new MqttCallback() {
        @Override
        public void connectionLost(Throwable throwable) {
            String str = throwable.toString();
            sendMessage(ACTION_CONNECTION_LOST, ACTION_CONNECTION_LOST, str);
            Log.e(TAG, "connectionLost case : " + str);
            startReconnect();
        }

        @Override
        public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
            String str = new String(mqttMessage.getPayload());
            sendMessage(ACTION_MESSAGE_ARRIVED, s, str);
            Log.e(TAG, "topWord = " + s + " , mqttMessage : " + str);
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        }
    };

    private void sendMessage(String action, String topWord, String content){
        Intent intent = new Intent();
        intent.setAction(action);
        intent.putExtra("content", content);
        mContext.sendBroadcast(intent);
        LogUtils.e("开启广播，发送推送");
    }

    private MqttClientMgr(Context context){
        mContext = context;
    }

    public static MqttClientMgr getInstance(Context context){
        if(mInstance == null){
            mInstance = new MqttClientMgr(context);
        }
        return mInstance;
    }

    /**
     * 连接
     */
    public void clientConnect(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // MQTT的连接设置
                    MqttConnectOptions options = new MqttConnectOptions();
                    // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
                    options.setCleanSession(true);
                    // 设置连接的用户名
                    options.setUserName(userName);
                    // 设置连接的密码
                    options.setPassword(passWord.toCharArray());
                    // 设置超时时间 单位为秒
                    options.setConnectionTimeout(5);
                    // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
                    options.setKeepAliveInterval(10);
                    //setWill方法，如果项目中需要知道客户端是否掉线可以调用该方法。设置最终端口的通知消息
//                    MqttTopic topic = mClient.getTopic("close/" + CLIENT_ID);
//                    options.setWill(topic, ("close/" + CLIENT_ID).getBytes(), 0, true);
                    //启动连接
                    mClient.connect(options);
                    //遍历之前的订阅
                    List<String> list = new ArrayList<String>();
                    list.addAll(mTopWordList);
                    mTopWordList.clear();
                    for (String str : list){
                        subscribe(str);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    startReconnect();
                }
            }
        }).start();
    }

    /**
     * 初始化Client
     */
    //TODO 南宁mqtt 端口由61613改为 1883
    public void initClient(){
        // host为主机名，test为clientid即连接MQTT的客户端ID，一般以客户端唯一标识符表示，MemoryPersistence设置clientid的保存形式，默认为以内存保存
        try {
            mClient = new MqttClient("tcp://" + Constance.BASE_URL_NOPORT + ":1883"
                    , CLIENT_ID, new MemoryPersistence());
            //回调
            mClient.setCallback(mQttCallback);
        } catch (MqttException e) {
            ToastUtils.showLong("初始化推送失败");
            e.printStackTrace();
        }
    }

    /**
     * 重新连接
     */
    public void startReconnect() {
        if(true){
            return;
        }
        if (!mbIsReconnect){
            mbIsReconnect = true;
            disconnect();
            scheduler = Executors.newSingleThreadScheduledExecutor();
            scheduler.scheduleAtFixedRate(new Runnable() {
                public void run() {
                    if (!mClient.isConnected()) {
                        try {
                            mClient = new MqttClient("tcp://" + Constance.BASE_URL_NOPORT + ":1883"
                                    , CLIENT_ID, new MemoryPersistence());
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        //回调
                        mClient.setCallback(mQttCallback);
                        clientConnect();
                    }else{
                        Log.i(TAG, "重连成功，关闭重连");
                        scheduler.shutdown();
                        mbIsReconnect = false;
                    }
                }
            }, 0, 10 * 1000, TimeUnit.MILLISECONDS);
        }
    }

    /**
     * 订阅
     */
    public void subscribe(final String str) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //订阅消息
                    int[] Qos  = {2};
                    String[] topic = {str};
                    mClient.subscribe(topic, Qos);
                    mTopWordList.add(str);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 取消订阅
     * @param str
     */
    public void unSubscribe(String str){
        try {
            mClient.unsubscribe(str);
            mTopWordList.remove(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 断开连接
     */
    public void disconnect() {
         try {
            mClient.disconnect();
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

} 